## Project: CueAnon
## Authors: Benjamin S. Noble and Taylor N. Carlson
## Code for conjoint experiment
## Replicates Figures 3-4, all Figures in Appendix C.

library(officer)
library(multiwayvcov)
library(margins)
library(tidyverse)
library(estimatr)
library(ggpubr)
library(cregg) 

source('ggtheme_baselike.R') # custom ggplot theme
# load data
dat_stack <- read_csv('conjoint_df.csv') %>% 
  # convert characters to factors
  mutate_at(vars(party:imm, resp_gop, resp_dem), as.factor) %>% 
  # remove independents
  filter(resp_gop == 1 | resp_dem == 1)

# final sample size 
dat_stack %>% 
  group_by(resp_dem, resp_gop, id) %>% 
  summarise() %>% 
  ungroup() %>% 
  group_by(resp_dem, resp_gop) %>% 
  summarise(n = n()) 

# --------------------------------------------------------------------------- #

# Table C1, balance
demo <- read_csv('conjoint_demo.csv')

demo %>%   
  summarise_all(~mean(., na.rm = T)) %>% 
  t() %>% 
  round(.,2) 

# --------------------------------------------------------------------------- #

plot_labs <- tibble(feature = c('gender', 'party', 'qanon', 'impeach', 'imm', 
    'econ', 'infra', 'prior'),
  cat = c('Sex', 'Party', 'QAnon', 'Impeachment', 'Immigration', 'Economics', 
    'Infrastructure', 'Prior Office')) %>% 
  mutate(cat_ord = factor(cat, levels = c("QAnon", "Party", "Sex", 
    "Prior Office", 'Impeachment', 'Immigration', 'Economics', 
    'Infrastructure')))

# Figure 3
# conjoint amce, vote choice dv
vote_choice_base <- cj(dat_stack, Y ~ gender + party + qanon + impeach + 
  imm + econ + infra + prior, id = ~id)
# conjoint amce, vote choice dv by party
vote_choice_byparty <- cj(dat_stack, Y ~ gender + party + qanon + impeach + 
  imm + econ + infra + prior, id = ~id, by = ~resp_gop)

# human readable feature labels
feat_labs <- tibble(label = c('Female', 'Male', 'Democrat', 'Republican', 
    'Did Not Support QAnon', 'Supported QAnon','Opposed\nTrump Impeachment', 
    'Supports\nTrump Impeachment', 'Opposes Wall', 'Supports Wall',
    'Higher Taxes,\nMore Services', 'Lower Taxes,\nFewer Services', 
    'Opposes\nInfrastructure Bill', 'Supports\nInfrastructure Bill',
    'No Prior Experience', 'State Representative', 'U.S. Senator'),
  level = vote_choice_base$level)

# combine output
vote_choice_all <- bind_rows(vote_choice_base %>% 
    mutate(resp_gop = as.factor(-1)), 
  vote_choice_byparty) %>% 
  # add plot labels
  left_join(plot_labs) %>% 
  # add feature labels
  left_join(feat_labs) %>%
  # add legend
  mutate(resp_gop = case_when(resp_gop == -1 ~ 'Full Sample', 
    resp_gop == 0 ~ 'Democrats',
    resp_gop == 1 ~ 'Republicans'))

## Figure 3
vote_choice_plot <- ggplot(vote_choice_all, aes(x = estimate, y = label, 
    color = resp_gop, shape = resp_gop)) + 
  geom_point(position = position_dodge2(1, reverse =T), size = 2) + 
  geom_errorbarh(aes(y = label, xmin = lower, xmax = upper), height = 0,
    position = position_dodge(-1)) +
  scale_color_manual(values = c('#9F9F9D', 'black', '#666666')) + 
  facet_grid(vars(cat_ord), scales = "free") +
  geom_vline(xintercept = 0, linetype = 'dashed') + 
  labs(x = '\nAMCE, Candidate Choice', y ='', color = '', shape = '') + 
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), panel.background = element_blank(), 
        panel.border = element_rect(colour = 'black', fill = NA),
        strip.background = element_rect(color = "black", size = .75))

# Figure C1, marginal means
# conjoint marginal means, vote choice dv
mm_all <- cj(dat_stack, Y ~ gender + party + qanon + impeach + imm + econ + 
  infra + prior, id = ~id, estimate = 'mm')
# conjoint marginal means, vote choice dv by party
mm_gop <- cj(dat_stack, Y ~ gender + party + qanon + impeach + imm + econ + 
  infra + prior, id = ~id, estimate = 'mm', by = ~resp_gop)

# combine output
mm_comb <- bind_rows(mm_all %>% mutate(resp_gop = as.factor(-1)), mm_gop) %>% 
  # add plot labels
  left_join(plot_labs) %>% 
  # add feature labels
  left_join(feat_labs) %>% 
  # add legend
  mutate(resp_gop = case_when(resp_gop == -1 ~ 'Full Sample', 
    resp_gop == 0 ~ 'Democrats',
    resp_gop == 1 ~ 'Republicans'))

## Figure C1
mm_vote <- ggplot(mm_comb, aes(x = estimate, y = label, color = resp_gop, shape = resp_gop)) + 
  geom_point(position = position_dodge2(1, reverse =T), size = 2) + 
  geom_errorbarh(aes(y = label, xmin = lower, xmax = upper), height = 0, position = position_dodge(-1)) +
  scale_color_manual(values = c('#9F9F9D', 'black', '#666666')) + 
  facet_grid(vars(cat_ord), scales = "free") +
  geom_vline(xintercept = 0.5, linetype = 'dashed') + 
  labs(x = '\nMarginal Mean, Candidate Choice', y ='', color = '', shape = '') + 
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), panel.background = element_blank(), 
        panel.border = element_rect(colour = 'black', fill = NA),
        strip.background = element_rect(color = "black", size = .75))

# Figure C2
# conjoint analysis, republican primary (only gop respondents, only two republican candidates)
rep_primary <- cj(dat_stack %>% filter(resp_gop == 1 & primary == 1 & party == "Republican"), 
  Y ~ gender + qanon + impeach + imm + econ + infra + prior, id = ~id)
prim_plot_df <- rep_primary %>% 
# add plot labels
  left_join(plot_labs) %>%
  # add feature labels 
  left_join(feat_labs) 
  
## Figure C2
prim_plot <- ggplot(prim_plot_df, aes(x = estimate, y = label)) + 
  geom_point(position = position_dodge2(1, reverse =T), size = 2) + 
  geom_errorbarh(aes(y = label, xmin = lower, xmax = upper), height = 0, position = position_dodge(-1)) +
  facet_grid(vars(cat_ord), scales = "free") +
  geom_vline(xintercept = 0, linetype = 'dashed') + 
  labs(x = '\nAMCE, Candidate Choice in Republican Primary', y ='', color = '', shape = '') + 
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), panel.background = element_blank(), 
        panel.border = element_rect(colour = 'black', fill = NA),
        strip.background = element_rect(color = "black", size = .75))

# --------------------------------------------------------------------------- #

# Figure C3
# trust moderator
trust_mod <- cj(dat_stack %>% mutate(trust2 = as.factor(trust)), 
  Y ~ gender + qanon + impeach + imm + econ + infra + prior,
  id = ~id, estimate = 'amce', by = ~trust2)

trust_mes <- as_tibble(trust_mod) %>% 
  filter(grepl('QAnon', level) & !is.na(p)) %>% 
  mutate(mod = 'Trust in Media',
    level2 = rep('',4))

trust_me <- ggplot(trust_mes, aes(x = estimate, y = level2, shape = trust2)) + 
  geom_point(position = position_dodge(.5), size = 3) + 
  geom_errorbarh(aes(y = level2, xmin = lower, xmax = upper), position = position_dodge(.5), height = 0) +
  facet_wrap(~mod, ncol = 1) + 
  geom_vline(xintercept = 0, linetype = 'dashed') +
  scale_shape_manual(labels = c('None at all','Not very much','A fair amount','A great deal'), 
    values = c(15:18)) +
  labs(x = '\nAMCE, Candidate Choice', y = '', shape = '') +
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), 
    panel.grid.minor = element_blank(), panel.background = element_blank(), 
    panel.border = element_rect(colour = 'black', fill = NA),
    strip.background = element_rect(color = "black", size = .75),
    axis.ticks.y = element_blank()) +   
  guides(shape = guide_legend(nrow = 2, byrow = TRUE)) +
  rremove("ylab")

# anti-establishment moderator
antiestablish_mod <- cj(dat_stack %>% mutate(ae2 = as.factor(ceiling(antiestablish_scale))), 
  Y ~ gender + qanon + impeach + imm + econ + infra + prior,
  id = ~id, estimate = 'amce', by = ~ae2)

antiestablish_mes <- as_tibble(antiestablish_mod) %>% 
  filter(grepl('QAnon', level) & !is.na(p)) %>% 
  mutate(mod = 'Anti-Establishment Belief Scale',
    level2 = rep('',4))

ae_me <- ggplot(antiestablish_mes, aes(x = estimate, y = level2, shape = ae2)) + 
  geom_point(position = position_dodge(.5), size = 3) + 
  geom_errorbarh(aes(y = level2, xmin = lower, xmax = upper), position = position_dodge(.5), height = 0) +
  facet_wrap(~mod, ncol = 1) + 
  geom_vline(xintercept = 0, linetype = 'dashed') +
  scale_shape_manual(labels = c('Disagree','Neither agree\nnor disagree','Agree', 'Strongly\nagree'),
    values = c(15:18)) +
  labs(x = '\nAMCE, Candidate Choice', y = '', shape = '') +
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), 
    panel.grid.minor = element_blank(), panel.background = element_blank(), 
    panel.border = element_rect(colour = 'black', fill = NA),
    strip.background = element_rect(color = "black", size = .75),
    axis.ticks.y = element_blank()) +   
  rremove("ylab")

# qanon belief moderator
qanon_mod <- cj(dat_stack %>% mutate(bq2 = as.factor(believe_q)), 
  Y ~ gender + qanon + impeach + imm + econ + infra + prior,
  id = ~id, estimate = 'amce', by = ~bq2)

q_mes <- as_tibble(qanon_mod) %>% 
  filter(grepl('QAnon', level) & !is.na(p)) %>% 
  mutate(mod = 'Believer in QAnon',
    level2 = rep('',5))

qanon_me <- ggplot(q_mes, aes(x = estimate, y = level2, shape = bq2)) + 
  geom_point(position = position_dodge(.5), size = 3) + 
  geom_errorbarh(aes(y = level2, xmin = lower, xmax = upper), position = position_dodge(.5), height = 0) +
  facet_wrap(~mod, ncol = 1) + 
  geom_vline(xintercept = 0, linetype = 'dashed') +
  scale_shape_manual(labels = c('Strongly\ndisagree','Disagree','Neither agree\nnor disagree','Agree', 'Strongly\nagree'),
    values = c(1,15:18)) +
  labs(x = '\nAMCE, Candidate Choice', y = '', shape = '') +
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), 
    panel.grid.minor = element_blank(), panel.background = element_blank(), 
    panel.border = element_rect(colour = 'black', fill = NA),
    strip.background = element_rect(color = "black", size = .75),
    axis.ticks.y = element_blank()) +   
  guides(shape = guide_legend(nrow = 2, byrow = TRUE)) +
  rremove("ylab")

# right-wing news moderator
alt_news_mod <- cj(dat_stack %>% mutate(alt_right_news = as.factor(alt_right_news)), 
  Y ~ gender + party + qanon + impeach + imm + econ + infra + prior,
  id = ~id, by = ~alt_right_news, estimate = 'amce')

alt_news_amce <- as_tibble(alt_news_mod) %>% 
  filter(grepl('QAnon', level) & !is.na(p)) %>% 
  mutate(mod = 'Alt-Right Media Usage',
    level2 = c('',''))

alt_news_plot <- ggplot(alt_news_amce, aes(x = estimate, y = level2, shape = alt_right_news)) + 
  geom_point(position = position_dodge(.5), size = 3) + 
  geom_errorbarh(aes(y = level2, xmin = lower, xmax = upper), position = position_dodge(.5), height = 0) +
  facet_wrap(~mod, ncol = 1) + 
  geom_vline(xintercept = 0, linetype = 'dashed') +
  scale_shape_manual(labels = c('Never/Once', 'Several Times/Daily'),
    values = c(1,16)) +
  labs(x = '\nAMCE, Candidate Choice', y = '', shape = '') +
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), panel.background = element_blank(), 
        panel.border = element_rect(colour = 'black', fill = NA),
        strip.background = element_rect(color = "black", size = .75),
        axis.ticks.y = element_blank()) + 
  rremove("ylab")

# fox news moderator
fox_mod <- cj(dat_stack %>% mutate(fox4 = as.factor(fox4)), 
  Y ~ gender + party + qanon + impeach + imm + econ + infra + prior,
  id = ~id, by = ~fox4, estimate = 'amce')

fox_amce <- as_tibble(fox_mod) %>% 
  filter(grepl('QAnon', level) & !is.na(p)) %>% 
  mutate(mod = 'Fox News Usage',
    level2 = rep('',4))

fox_plot <- ggplot(fox_amce, aes(x = estimate, y = level2, shape = fox4)) + 
  geom_point(position = position_dodge(.5), size = 3) + 
  geom_errorbarh(aes(y = level2, xmin = lower, xmax = upper), position = position_dodge(.5), height = 0) +
  facet_wrap(~mod, ncol = 1) + 
  geom_vline(xintercept = 0, linetype = 'dashed') +
  scale_shape_manual(labels = c('Never', 'Once', 'Several times', 'Daily'),
    values = c(15:18)) +
  labs(x = '\nAMCE, Candidate Choice', y = '', shape = '') +
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), panel.background = element_blank(), 
        panel.border = element_rect(colour = 'black', fill = NA),
        strip.background = element_rect(color = "black", size = .75),
        axis.ticks.y = element_blank()) + 
  rremove("ylab")

# make full plot
figc3 <- ggarrange(trust_me, ae_me, alt_news_plot, qanon_me, fox_plot, ncol = 2, nrow = 3)
figc3_y <- annotate_figure(figc3, top = text_grob('AMCE of Candidate QAnon Support on Probability\nof Choosing Candidate for Various Subgroups'))## Figure C3

# --------------------------------------------------------------------------- #

# Figure C4
# conjoint amce, favorability dv
fav_amce <- cj(dat_stack, likert_favor ~ gender + party + qanon + impeach + 
  imm + econ + infra + prior, id = ~id)
# conjoint amce, favorability dv by party
fav_amce_byparty <- cj(dat_stack, likert_favor ~ gender + party + qanon + 
  impeach + imm + econ + infra + prior, id = ~id, by = ~resp_gop)

# combine output
fav_all <- bind_rows(fav_amce %>% mutate(resp_gop = as.factor(-1)), 
    fav_amce_byparty) %>% 
  left_join(plot_labs) %>% # add plot labels
  left_join(feat_labs) %>% # add feature labels
  mutate(resp_gop = case_when(resp_gop == -1 ~ 'Full Sample', # add legend
    resp_gop == 0 ~ 'Democrats',
    resp_gop == 1 ~ 'Republicans'))

fav_plot <- ggplot(fav_all, aes(x = estimate, y = label, 
    color = resp_gop, shape = resp_gop)) + 
  geom_point(position = position_dodge2(1, reverse =T), size = 2) + 
  geom_errorbarh(aes(y = label, xmin = lower, xmax = upper), height = 0,
    position = position_dodge(-1)) +
  scale_color_manual(values = c('#9F9F9D', 'black', '#666666')) + 
  facet_grid(vars(cat_ord), scales = "free") +
  geom_vline(xintercept = 0, linetype = 'dashed') + 
  labs(x = '\nAMCE, Favorability', y ='', color = '', shape = '') + 
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), 
    panel.grid.minor = element_blank(), panel.background = element_blank(), 
    panel.border = element_rect(colour = 'black', fill = NA),
    strip.background = element_rect(color = "black", size = .75))

# favorability, marginal means
mm_all_fav <- cj(dat_stack, likert_favor ~ gender + party + qanon + impeach + 
  imm + econ + infra + prior, id = ~id, estimate = 'mm')
mm_gop_fav <- cj(dat_stack, likert_favor ~ gender + party + qanon + impeach + 
  imm + econ + infra + prior, id = ~id, estimate = 'mm', by = ~resp_gop)

mm_comb_fav <- bind_rows(mm_all_fav %>% mutate(resp_gop = as.factor(-1)), 
    mm_gop_fav) %>% 
  left_join(plot_labs) %>% 
  left_join(feat_labs) %>% 
  mutate(resp_gop = case_when(resp_gop == -1 ~ 'Full Sample',
    resp_gop == 0 ~ 'Democrats',
    resp_gop == 1 ~ 'Republicans'))

mm_fav <- ggplot(mm_comb_fav, aes(x = estimate, y = label, color = resp_gop, shape = resp_gop)) + 
  geom_point(position = position_dodge2(1, reverse =T), size = 2) + 
  geom_errorbarh(aes(y = label, xmin = lower, xmax = upper), height = 0, position = position_dodge(-1)) +
  scale_color_manual(values = c('#9F9F9D', 'black', '#666666')) + 
  facet_grid(vars(cat_ord), scales = "free") +
  geom_vline(xintercept = 4, linetype = 'dashed') + 
  labs(x = '\nMarginal Mean, Favorability', y ='', color = '', shape = '') + 
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), panel.grid.minor = element_blank(), panel.background = element_blank(), panel.border = element_rect(colour = 'black', fill = NA),
        strip.background = element_rect(color = "black", size = .75))

# Figure C4
fav_comb <- ggarrange(fav_plot, mm_fav, common.legend = T, legend = 'bottom') 

# --------------------------------------------------------------------------- #

# Figure 3
# conjoint amce, ideology choice dv
ideology_base <- cj(dat_stack, likert_ideology ~ gender + party + qanon + impeach + 
  imm + econ + infra + prior, id = ~id)
# conjoint amce, vote choice dv by party
ideology_byparty <- cj(dat_stack, likert_ideology ~ gender + party + qanon + impeach + 
  imm + econ + infra + prior, id = ~id, by = ~resp_gop)

# combine output
ideology_all <- bind_rows(ideology_base %>% mutate(resp_gop = as.factor(-1)), 
    ideology_byparty) %>% 
  left_join(plot_labs) %>% # add plot labels
  left_join(feat_labs) %>% # add feature labels
  mutate(resp_gop = case_when(resp_gop == -1 ~ 'Full Sample', # add legend
    resp_gop == 0 ~ 'Democrats',
    resp_gop == 1 ~ 'Republicans'))

ideology_plot <- ggplot(ideology_all, aes(x = estimate, y = label, 
    color = resp_gop, shape = resp_gop)) + 
  geom_point(position = position_dodge2(1, reverse =T), size = 2) + 
  geom_errorbarh(aes(y = label, xmin = lower, xmax = upper), height = 0,
    position = position_dodge(-1)) +
  scale_color_manual(values = c('#9F9F9D', 'black', '#666666')) + 
  facet_grid(vars(cat_ord), scales = "free") +
  geom_vline(xintercept = 0, linetype = 'dashed') + 
  labs(x = '\nAMCE, Perception of Ideological Conservatism', y ='', color = '', shape = '') + 
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), 
    panel.grid.minor = element_blank(), panel.background = element_blank(), 
    panel.border = element_rect(colour = 'black', fill = NA),
    strip.background = element_rect(color = "black", size = .75))

# Figure C5
# conjoint marginal means, ideology choice dv
mm_ideo_all <- cj(dat_stack, likert_ideology ~ gender + party + qanon + 
  impeach + imm + econ + infra + prior, id = ~id, estimate = 'mm')
# conjoint marginal means, ideology choice dv by party
mm_ideo_gop <- cj(dat_stack, likert_ideology ~ gender + party + qanon + 
  impeach + imm + econ + infra + prior, id = ~id, estimate = 'mm', by = ~resp_gop)

# combine output
mm_ideo_comb <- bind_rows(mm_ideo_all %>% mutate(resp_gop = as.factor(-1)), mm_ideo_gop) %>% 
  left_join(plot_labs) %>% # add plot labels
  left_join(feat_labs) %>% # add feature labels
  mutate(resp_gop = case_when(resp_gop == -1 ~ 'Full Sample', # add legend
    resp_gop == 0 ~ 'Democrats',
    resp_gop == 1 ~ 'Republicans'))

## Figure C5
mm_ideo_vote <- ggplot(mm_ideo_comb, aes(x = estimate, y = label, color = resp_gop, shape = resp_gop)) + 
  geom_point(position = position_dodge2(1, reverse =T), size = 2) + 
  geom_errorbarh(aes(y = label, xmin = lower, xmax = upper), height = 0, position = position_dodge(-1)) +
  scale_color_manual(values = c('#9F9F9D', 'black', '#666666')) + 
  facet_grid(vars(cat_ord), scales = "free") +
  geom_vline(xintercept = 4, linetype = 'dashed') + 
  labs(x = '\nMarginal Mean, Perception of Ideological Conservatism', y ='', color = '', shape = '') + 
  theme(legend.position = 'bottom', panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), panel.background = element_blank(), 
        panel.border = element_rect(colour = 'black', fill = NA),
        strip.background = element_rect(color = "black", size = .75))
